#include<iostream>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/types.h>        
#include<sys/socket.h>
#include<stdlib.h> //exit
#include<string.h> //memset
using namespace std;
//服务端:
// 1.服务端将来是这么启动的 ./udp_server port 服务端提供的是死循环的服务
// 2.服务器不建议绑定固定的ip  建议绑定INADDR_ANY ==>让系统帮我们绑定  可以从任意一个网卡当中读取数据
// 由于UDP是无连接的,所以绑定了之后就可以直接提供服务了(获取用户发送的数据)
// 3.流程：创建套接字 -> 绑定  -> 提供服务

// 丐版服务器:读取用户输入的内容,然后构建响应hello发送回去  

void Usage(std::string proc)
{
    cout << "Usage\n\t" << proc << " port" << endl;
    exit(1);
}
int main(int argc,char* argv[])
{
    if(argc != 2)
        Usage(argv[0]);
    //1.创建套接字
    int sock = socket(AF_INET,SOCK_DGRAM,0);
    if(sock < 0)
    {
      perror("socket");
      exit(2);
    }
    cout <<"server---套接字创建成功...."<<endl;

    uint16_t port = atoi(argv[1]);//将字符串端口号->整数端口号
    //2.绑定
    struct sockaddr_in local;//用于填充服务器的网络相关信息
    memset(&local,0,sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(port);//将端口号由主机序->网络字节序
    local.sin_addr.s_addr = INADDR_ANY;
    if(bind(sock,(struct sockaddr*)&local,sizeof(local) )< 0)
    {
        perror("bind");
        exit(3);
    }
    cout << "server---绑定成功....."<<endl;
    #define NUM 1024 //缓冲区大小
    //3.死循环提供服务
    cout <<"开始提供服务....." << endl;
    for(;;)
    {
        char buf[NUM] = {0};
        struct sockaddr_in peer;//记录客户端的网络相关信息
        socklen_t len = sizeof(peer);//期望读取的该结构体的大小 ->输入输出型参数
        ssize_t cnt = recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&peer,&len); 
        if(cnt > 0) //cnt:实际读取的字节个数
        {
            buf[cnt] = 0;
            cout << "client# " << buf << endl;
        }
        else
        {
            perror("recvfrom");
            continue; 
        }
        //此时peer中记录着客户端的网络相关信息,作为sendto的接收数据的主机
        //构建一个hello响应回去
        string msg = "hello";
        sendto(sock,msg.c_str(),msg.size(),0,(struct sockaddr*)&peer,len);
    }
    return 0;
}